import os
import wget
import tarfile
import requests
import datetime
import logging

from callgraph_gen.callgraph_gen import PkgAPIs
from neo4jDBOP import neo4jDBOP
from import_graph.import_graph import ImportGraph
from inherit_graph.inherit_graph import InheritGraph

neo4j_conf = {
    "uri" : "neo4j://211.71.15.39:7685",
    "user" : "neo4j",
    "password" : "pysr"
}
# browser : 211.71.15.39:7472
# 211.71.15.39:7471

neo4j_conf_readonly = {
    "uri" : "neo4j://211.71.15.39:9687",
    "user" : "neo4j",
    "password" : "python"
}
# browser : 211.71.15.39:9474
# 211.71.15.39:9473

DBOP = neo4jDBOP(neo4j_conf=neo4j_conf)

pkgs_list = []
pkgs_set = set()

logger = logging.getLogger()
logger.setLevel(logging.DEBUG)

logfile = "logs/log%s.txt" % datetime.date.today().strftime('%y%m%d')
fh = logging.FileHandler(logfile, mode='a')
fh.setLevel(logging.DEBUG)

ch = logging.StreamHandler()
ch.setLevel(logging.INFO)

formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
ch.setFormatter(formatter)

logger.addHandler(fh)
logger.addHandler(ch)

inherit_graph = InheritGraph()

def download_dependencies(name, version):
    """ 下载当前版本包，以及其所有依赖 """
    pkg_id = name + "@" + version
    if pkg_id not in pkgs_set:
        pkgs_set.add(pkg_id)
        pkgs_list.append((name, version))

    # 下载name-version.tar.gz，解压并生成import graph
    tar_name = "pkgs/" + name + "-" + version + ".tar.gz"
    dir_name = "pkgs/" + name + "-" + version + "/"
    flag = DBOP.checkPkgDownloaded(name=name, version=version)
    if len(flag) == 0 or not flag[0]:
        # logging.info("download package ", pkg_id, ", begin time: ", datetime.datetime.now().timestamp())
        if not os.path.exists(tar_name):
            url = "https://pypi.org/pypi/%s/%s/json" % (name, version)
            response = requests.get(url)
            response_dict = response.json()
            releases = response_dict['urls']
            for release in releases:
                pkg_url = release['url']
                if pkg_url.endswith('.tar.gz'):
                    wget.download(pkg_url, out=tar_name)
        if not os.path.exists(dir_name):
            tf = tarfile.open(tar_name)
            tf.extractall("pkgs")
        logger.info("      download package %s." % pkg_id)
        # absolute_path = os.path.abspath(dir_name)
        # print(absolute_path, name + "-" + version)
        import_graph = ImportGraph(pkg_name=name, version=version)
        import_graph.generate_file_system_graph(import_graph.absolute_path, import_graph.relative_path)
        logger.info("      generate file system graph of package %s." % pkg_id)
        import_graph.API_mapping()
        logger.info("      mapping API for package %s." % pkg_id)
        inherit_graph.dict_update(base_dict=import_graph.base_dict, import_dict=import_graph.import_dict)
        DBOP.insertPypiPackage(name=name, version=version, downloaded=True)
        DBOP.insertFilesystemContains(pkg_id=pkg_id, fully_qualified_name=name + "-" + version)
    # else:
        # logging.info("package ", pkg_id, " has been downloaded.")
    

    # 下载pkg：name-version的依赖项
    url = "https://libraries.io/api/PYPI/%s/%s/dependencies?api_key=d9767a0692bdfc4db28507b950196d4c" % (name, version)
    response = requests.get(url)
    response_dict = response.json()
    # print(response_dict['dependencies'])
    for pkg in response_dict['dependencies']:
        # self.dependencies.append((pkg['name'], pkg["latest"]))
        # flag = DBOP.checkPkgDownloaded(name=self.pkg_name, version=self.version)
        # if len(flag) == 0 or not flag[0]:
        download_dependencies(pkg['name'], pkg["latest"])
    logger.info("      download dependencies of package %s." % pkg_id)
    # DBOP.labelPkgAlldependencies(name=name, version=version)

if __name__ == "__main__":
    # package_name = sys.argv[1]
    # package_version = sys.argv[2]

    package_name = "requests"
    package_version = "2.28.2"
    begin_time = datetime.datetime.now().timestamp()
    logger.info("analyse supply chain for package %s." % (package_name + "@" + package_version))
    download_dependencies(package_name, package_version)
    inherit_graph.generate_inherit_graph()
    for pkg in pkgs_list:
        flag = DBOP.checkPkgAnalysed(name=pkg[0], version=pkg[1])
        if len(flag) == 0 or not flag[0]:
            pkgAPIs = PkgAPIs(pkg[0], pkg[1])
            pkgAPIs.get_pyfiles(pkgAPIs.dir_name)
            pkgAPIs.callgraph_gen()
            logger.info("      generate call graph of package %s." % (pkg[0] + "@" + pkg[1]))
            pkgAPIs.callgraph_store()
            logger.info("      store call graph of package %s." % (pkg[0] + "@" + pkg[1]))
        DBOP.labelPkgAnalysed(name=pkg[0], version=pkg[1])
    end_time = datetime.datetime.now().timestamp()
    logger.info("analyse supply chain for package %s, total time: %s." % (package_name + "@" + package_version, end_time - begin_time))